package com.google.adwords.samples.disapproved;

import com.google.adwords.samples.convert.XmlToCsvConverter;
import com.google.api.adwords.v10.AdGroupStatus;
import com.google.api.adwords.v10.AggregationType;
import com.google.api.adwords.v10.CampaignStatus;
import com.google.api.adwords.v10.CustomReportJob;
import com.google.api.adwords.v10.CustomReportOption;
import com.google.api.adwords.v10.KeywordStatus;
import com.google.api.adwords.v10.ReportJobStatus;

import org.xml.sax.SAXException;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.logging.Logger;

import javax.xml.parsers.ParserConfigurationException;

/**
 * Find Disapproved Keywords
 * @author alecmgo@gmail.com (Alec Go)
 *
 */
public class DisapprovedKeywords {
  
  private static Logger logger = Logger.getLogger(DisapprovedKeywords.class.getName());

  private static final long CHECK_REPORT_INTERVAL = 30000;
  private static final String OUTPUT_FILENAME_SUFFIX = "-keywords.xml";
  
  /**
   * Command-line entry point for this sample code
   * @param args
   * @throws Exception
   */
  public static void main(String[] args) throws Exception {
    String account = "";
    int continueAfter = 0;
    
    //Optional account parameter, if it is different from what is specified in the properties file
    if(args.length > 0) {
      account = args[0];
    } 

    //Optional "continuation" parameter
    if(args.length > 1) {
      continueAfter = Integer.parseInt(args[1]);
    }

    run(account, continueAfter);
  }
  
  /**
   * Run the disapproval keyword report
   * @param account
   * @param continueAfter
   * @throws AppException
   */
  private static void run(String account, int continueAfter) throws AppException {
    String[] accounts = (new AdWordsInterface(account)).getClientAccounts();
    for(int i = 0; i < accounts.length; i++) {
      if(i >= continueAfter) {
        logger.info(i + ". Analyzing: " + accounts[i]);
        getDisapprovedKeywordsReport(accounts[i]);
      } else {
        logger.info(i + ". Skipping: " + accounts[i]);
      }
    }
    
    //Convert the XML Reports to CSV.  Use the current working directory.
    File dir = new File(System.getProperty("user.dir"));
    try {
      XmlToCsvConverter x = new XmlToCsvConverter(dir);
      x.processDirectory(dir);
    } catch(ParserConfigurationException e) {
      throw new AppException(e);
    } catch(IOException e) {
      throw new AppException(e);
    } catch(SAXException e) {
      throw new AppException(e);
    }
  }  

  /**
   * Writes a report with the disapproved keywords. Much of this code has been
   * copied from the AdWords API from
   * http://google-api-adwords-java.googlecode.com/svn/trunk/examples/ <br/>
   * This function determines what fields are outputted to the file. If the
   * outputs change, then the <code>Constants.KEYWORD_REPORT_HEADER_LINE</code>
   * must change.
   * 
   * @param account
   * @throws AppException
   */
  public static void getDisapprovedKeywordsReport(String account) throws AppException {
    AdWordsInterface adwordsInterface = new AdWordsInterface(account);
    
    // Create the report job we're going to send
    CustomReportJob reportJob = new CustomReportJob();

    // Set the aggregation period
    reportJob.setAggregationType(AggregationType.Daily);
    
    // Set Date range for today
    reportJob.setStartDay(new Date()); // defaults to today
    reportJob.setEndDay(new Date()); // defaults to today
    
    // CustomReports lets you specify exactly what you want to retrieve in the report
    CustomReportOption[] customOptions = { CustomReportOption.AccountName,
        CustomReportOption.Campaign, CustomReportOption.CampaignId,
        CustomReportOption.CampaignStatus, CustomReportOption.AdGroup,
        CustomReportOption.AdGroupId, CustomReportOption.AdGroupStatus,
        CustomReportOption.Keyword, CustomReportOption.KeywordId,
        CustomReportOption.KeywordStatus, CustomReportOption.Impressions};
    reportJob.setCustomOptions(customOptions);

    // Name this report job
    reportJob.setName("Disapproved Keywords - " + account);
    
    // Specify only active Campaigns, enabled AdGroups, and Disapproved Keywords
    reportJob.setCampaignStatuses(new CampaignStatus[]{CampaignStatus.Active});
    reportJob.setAdGroupStatuses(new AdGroupStatus[]{AdGroupStatus.Enabled});
    reportJob.setKeywordStatuses(new KeywordStatus[]{KeywordStatus.Disapproved});
    reportJob.setIncludeZeroImpression(new Boolean (true)); 
    
    // Submit the request for the report
    long jobId = adwordsInterface.scheduleReportJob(reportJob);
    logger.info("Job ID: " + jobId);

    getReport(adwordsInterface, account, jobId);
  }
  
  /**
   * This method is used for emergency recoveries.
   * @param account
   * @param jobId
   * @throws AppException
   */
  public static void getReport(AdWordsInterface adwordsInterface, String account, long jobId) throws AppException {
    // Wait until the report has been generated
    ReportJobStatus status = adwordsInterface.getReportJobStatus(jobId);
   
    while (status != ReportJobStatus.Completed
        && status != ReportJobStatus.Failed) {
      try {
        Thread.sleep(CHECK_REPORT_INTERVAL);
      } catch (InterruptedException e) {
        logger.severe(e.toString());
      }
      status = adwordsInterface.getReportJobStatus(jobId);
      logger.info("Report job status is " + status.toString());
    }

    if (status == ReportJobStatus.Failed) {
      logger.info("Job failed!");
    } else {
      // report is ready; download it
      logger.info("The report is ready!");

      // Download the report
      String url = adwordsInterface.getReportDownloadUrl(jobId);

      try {
        // Open URL connection
        URL u = new URL(url);
        URLConnection conn = u.openConnection();
        conn.connect();

        // Read each line of a report and save it to a file
        String filename = account + OUTPUT_FILENAME_SUFFIX;
        File file = new File(filename);

        FileWriter writer = new FileWriter(file);

        // Read each line of the report and print it out.
        BufferedReader reader =
            new BufferedReader(new InputStreamReader(conn.getInputStream()));

        String line = reader.readLine();
        while ((line != null)) {
          writer.write(line);
          line = reader.readLine();
        }

        logger.info("Report has been written to " + file);
        reader.close();
        writer.close();
      } catch (IOException e) {
        throw new AppException(e);
      }      
    } // closes the else
  }
}
